package io.skywalking.apm.plugin.ice.v3;

import com.zeroc.Ice.Request;
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.OfficialComponent;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * <p> IceV3DispatchInterceptor 服务端拦截器
 *
 * @author gaochuan
 * @version 0.1.0
 * @date 2022/2/14 13:31
 * @since 2022/2/14
 */
public class IceV3DispatchInterceptor implements InstanceMethodsAroundInterceptor {

    @Override
    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                             MethodInterceptResult result) throws Throwable {
        //判断参数
        if (allArguments[0] == null) {
            // illegal args, can't trace. ignore.
            return;
        }

        //获取请求request
        Request request = (Request) allArguments[0];

        //抓取ctx
        Map<String, String> ctx = request.getCurrent().ctx;

        ContextCarrier contextCarrier = new ContextCarrier();
        String operationName = request.getCurrent().operation;
        AbstractSpan span = ContextManager.createEntrySpan(operationName, contextCarrier)
                .start(System.currentTimeMillis());
        span.setComponent(new OfficialComponent(115, "ice-java"));
        SpanLayer.asRPCFramework(span);
        CarrierItem next = contextCarrier.items();
        while (next.hasNext()) {
            next = next.next();
            Object propertyValue = ctx.get(next.getHeadKey());
            if (propertyValue != null) {
                next.setHeadValue(propertyValue.toString());
            }
        }
        ContextManager.extract(contextCarrier);

    }

    @Override
    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                              Object ret) throws Throwable {
        ContextManager.stopSpan();
        return ret;

    }

    @Override
    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
                                      Class<?>[] argumentsTypes, Throwable t) {
        ContextManager.activeSpan().log(t);
    }
}
